use std::sync::{Arc, mpsc};

use redis::aio::MultiplexedConnection;

use redis_cache::{Cache, redis_args, redis_client, RedisCache, RedisCacheBuilder, RedisConnectInfo};

redis_args! {
    #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
    struct Demo {
        name: String,
        age: u8,
        hobby: Vec<String>,
    }
}

#[tokio::main]
async fn main() {
    cache_multi_get().await;
}

async fn get_cache_conn() -> MultiplexedConnection {
    let info = RedisConnectInfo::new(
        "172.18.2.249".to_owned(),
        4379,
        Some("!@admin".to_owned()),
        0,
    );
    let client = redis_client(info).await.unwrap();
    client.get_multiplexed_tokio_connection().await.unwrap()
}

async fn get_cache(conn: MultiplexedConnection) -> RedisCache {
    RedisCacheBuilder::default()
        .conn(conn)
        .expire(30 * 1000)
        .build()
        .unwrap()
}

async fn cache_multi_get() {
    let demo = Demo {
        name: "张三".to_owned(),
        age: 31,
        hobby: vec!["抽烟".to_owned(), "喝酒".to_owned(), "烫头".to_owned()],
    };
    let key = "order:100";
    let conn = get_cache_conn().await;
    let cache = Arc::new(get_cache(conn).await);

    let (tx, rx) = mpsc::channel::<()>();
    for _ in 0..10 {
        let tx = tx.clone();
        let cache = cache.clone();
        let demo = demo.clone();
        tokio::spawn(async move {
            let demo_clone = demo.clone();
            let r = cache
                .get(key, || {
                    Box::pin(async move {
                        Ok::<Option<Demo>, String>(Some(demo))
                    })
                })
                .await
                .unwrap();
            let r = r.unwrap();
            assert_eq!(r.name, demo_clone.name);
            assert_eq!(r.age, demo_clone.age);
            assert_eq!(r.hobby, demo_clone.hobby);
            drop(tx);
        });
    }
    drop(tx);
    while rx.recv().is_ok() {}
}